#ifndef __ENTITY_MANAGER_H__
#define __ENTITY_MANAGER_H__

#include <vector>
#include <unordered_map>
#include <unordered_set>
#include <memory>
#include <mutex>

#include "entt/entt.hpp"
#include "nlohmann/json.hpp"

#include "Engine/Point3.hpp"
#include "Engine/Vector3.hpp"

#include "concurrentqueue.h"
#include "GameSingleton.h"
#include "GameLock.hpp"


using namespace PocketSurvival::Engine;

namespace PocketSurvival
{
    class EntityManager : public SimpleSingletonItem
    {
        friend class SimpleSingleton;
    private:
        EntityManager();
        ~EntityManager();
        EntityManager(const EntityManager &) = delete;
        EntityManager(EntityManager &&) = delete;
        EntityManager &operator=(const EntityManager &) = delete;
        EntityManager &operator=(EntityManager &&) = delete;

        moodycamel::ConcurrentQueue<int32_t> m_recycleEntityIDQueue;
        int32_t m_endEntityID;
        SpinLock m_entityIDLock;

        // 实体的基础数据
        std::unordered_map<std::string, nlohmann::json> m_entityEssentialData;

    public:

        entt::entity createNewEntity();

        entt::entity createEntityByName(const std::string &essentityEntityName);

        entt::entity createEntityByEssentitalData(const nlohmann::json &essentialJson);

        void destoryEntity(entt::entity entity);

        /***********************************************************************************************************
         * @brief 添加实体的基础数据，注意：这个函数没有线程安全，只能在服务器初始化的时候调用
         * @param entityName 实体数据的名称
         * @param jsonData 具体的实体数据
        ***********************************************************************************************************/
        void addEssentialData(const std::string &entityName, const nlohmann::json &jsonData);

        /***********************************************************************************************************
         * @brief 加载文件形式的实体基础数据，需要以.json文件结尾
         * @param path 存放实体基础数据的文件夹
        ***********************************************************************************************************/
        void loadEssentitalFiles(const std::string &path);

        /***********************************************************************************************************
         * @brief 替换实体的基础数据，注意：这个函数没有线程安全，只能在服务器初始化的时候调用，若要替换的实体不能存在，结果跟添加一样
         * @param entityName 实体数据的名称
         * @param jsonData 具体的实体数据
        ***********************************************************************************************************/
        void replaceEssentialData(const std::string &entityName, const nlohmann::json &jsonData);

        inline bool tryGetEntityEssentialData(const std::string &entityName, nlohmann::json &outJson);

        void loadGame();
    };

    inline bool EntityManager::tryGetEntityEssentialData(const std::string &entityName, nlohmann::json &outJson)
    {
        auto it = m_entityEssentialData.find(entityName);
        if(it != m_entityEssentialData.end())
        {
            // 返回的是复制的版本
            outJson = it->second;
            return true;
        }
        return false;
    }

} // namespace PocketSurvival

#endif
